package com.sigmatrix.h5.service.rebate;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import org.springframework.transaction.annotation.Transactional;

import com.sigmatrix.h5.auth.ILoginUser;
import com.sigmatrix.h5.exception.MessageException;
import com.sigmatrix.h5.utils.CommonUtils;

/**
 * 抽象handler
 * 
 * @author wei.wang
 *
 * @param <T>
 */
public abstract class AbstractHandler<T extends RebateBaseInfo> implements IRebateHandle<T> {

	private List<PrepositInfoCollect<T>> prepositInfoCollectors = new ArrayList<>();

	private List<RebateIntercept<T>> rebateInterceptors = new ArrayList<>();

	private List<ObjectChoose<T>> objectChoosers = new ArrayList<>();

	private List<RebateAction<T>> rebateActions = new ArrayList<>();

	@Override
	public T getRebateBaseInfo(IRebateInput input, ILoginUser userInfo, String serialNum) {
		if (userInfo == null) {
			throw new MessageException("系统错误");
		}
		if (CommonUtils.isEmpty(userInfo.getDealerOrShopId())) {
			throw new MessageException("系统错误");
		}
		if (CommonUtils.isEmpty(input.getQrCode())) {
			throw new MessageException("QrCode不能为空。");
		}
		T rebateInfo = buildRebateBaseInfo();

		if (rebateInfo == null) {
			throw new MessageException("未初始化 rebateInfo 对象。");
		}
		rebateInfo.setUserInfo(userInfo);
		rebateInfo.setSerialNum(serialNum);

		for (PrepositInfoCollect<T> collector : prepositInfoCollectors) {
			collector.collect(rebateInfo);
		}

		return chooseActivityAndStrategy(rebateInfo);
	}

	/**
	 * 选择活动和策略
	 * 
	 * @param t
	 * @return
	 */
	public T chooseActivityAndStrategy(T t) {

		return t;
	}

	@Override
	public boolean isRebateAllowed(T info) {
		for (RebateIntercept<T> rebateInterceptor : rebateInterceptors) {
			if (!rebateInterceptor.isRebateAllowed(info)) {
				return false;
			}
		}
		return true;
	}

	@Override
	public RebateObjects chooseObject(T info, RebateCandidate candidate) {
		RebateObjects objects = new RebateObjects();
		for (ObjectChoose<T> objectChooser : objectChoosers) {
			objects = objectChooser.choose(info, candidate, objects);
		}
		return objects;
	}

	@Override
	public void doRebate(RebateObjects obj, T info) {
		for (RebateAction<T> rebateAction : rebateActions) {
			rebateAction.doAction(obj, info);
		}
	}

	@Override
	@Transactional
	public IRebateResult doProcess(IRebateInput input, ILoginUser userInfo) {
		IRebateResult f = null;
		RebateObjects chooseObject = null;
		RebateCandidate rebateCandidate = null;
		T rebateBaseInfo = null;
		Exception exception = null;
		try {
			rebateBaseInfo = getRebateBaseInfo(input, userInfo, generateSerialNum());
			if (!isRebateAllowed(rebateBaseInfo)) {
				f = convert(chooseObject, rebateBaseInfo, input, userInfo);
				return f;
			}
			rebateCandidate = getRebateCandidate(rebateBaseInfo);
			chooseObject = chooseObject(rebateBaseInfo, rebateCandidate);
			doRebate(chooseObject, rebateBaseInfo);
			f = convert(chooseObject, rebateBaseInfo, input, userInfo);
		} catch (Exception e) {
			exception = e;
			throw e;
		} finally {
			if (exception instanceof MessageException) {
				log(chooseObject, rebateBaseInfo, input, userInfo, (MessageException) exception);
			} else if (exception == null) {
				log(chooseObject, rebateBaseInfo, input, userInfo, null);
			}
		}
		return f;
	}

	/**
	 * 记录日志。
	 * 
	 * @param chooseObject
	 * @param rebateBaseInfo
	 * @param input
	 * @param userInfo
	 */
	protected void log(RebateObjects chooseObject, T rebateBaseInfo, IRebateInput input, ILoginUser userInfo,
			MessageException exception) {
	}

	/**
	 * 转换结果。
	 * 
	 * @param chooseObject
	 * @param rebateBaseInfo
	 * @param input
	 * @param userInfo
	 * @return
	 */
	protected abstract IRebateResult convert(RebateObjects chooseObject, T rebateBaseInfo, IRebateInput input,
			ILoginUser userInfo);

	/**
	 * 生成流水号
	 * 
	 * @return
	 */
	protected String generateSerialNum() {
		return UUID.randomUUID().toString();
	}

	@Override
	public void addColletor(PrepositInfoCollect<T> colletor) {
		prepositInfoCollectors.add(colletor);
	}

	@Override
	public void addInterceptor(RebateIntercept<T> interceptor) {
		rebateInterceptors.add(interceptor);
	}

	@Override
	public void addChooser(ObjectChoose<T> chooser) {
		objectChoosers.add(chooser);
	}

	@Override
	public void addAction(RebateAction<T> action) {
		rebateActions.add(action);
	}

}
